{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 将tfkeras转化为estimator--titanic问题"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2.0.0\n",
      "sys.version_info(major=3, minor=6, micro=10, releaselevel='final', serial=0)\n",
      "matplotlib 3.1.2\n",
      "numpy 1.18.1\n",
      "pandas 0.25.3\n",
      "sklearn 0.22.1\n",
      "tensorflow 2.0.0\n",
      "tensorflow_core.keras 2.2.4-tf\n"
     ]
    }
   ],
   "source": [
    "# 导入\n",
    "import matplotlib as mpl\n",
    "import matplotlib.pyplot as plt\n",
    "%matplotlib inline\n",
    "import numpy as np\n",
    "import sklearn\n",
    "import pandas as pd\n",
    "import os\n",
    "import sys\n",
    "import time\n",
    "import tensorflow as tf\n",
    "from tensorflow import keras\n",
    "\n",
    "print(tf.__version__)\n",
    "print(sys.version_info)\n",
    "for module in mpl,np,pd,sklearn,tf,keras:\n",
    "    print(module.__name__,module.__version__)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## titanic生存预测问题\n",
    "哪些乘客获救，哪些没有\n",
    "### 数据集探索"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "   survived     sex   age  n_siblings_spouses  parch     fare  class     deck  \\\n",
      "0         0    male  22.0                   1      0   7.2500  Third  unknown   \n",
      "1         1  female  38.0                   1      0  71.2833  First        C   \n",
      "2         1  female  26.0                   0      0   7.9250  Third  unknown   \n",
      "3         1  female  35.0                   1      0  53.1000  First        C   \n",
      "4         0    male  28.0                   0      0   8.4583  Third  unknown   \n",
      "\n",
      "   embark_town alone  \n",
      "0  Southampton     n  \n",
      "1    Cherbourg     n  \n",
      "2  Southampton     y  \n",
      "3  Southampton     n  \n",
      "4   Queenstown     y  \n",
      "   survived     sex   age  n_siblings_spouses  parch     fare   class  \\\n",
      "0         0    male  35.0                   0      0   8.0500   Third   \n",
      "1         0    male  54.0                   0      0  51.8625   First   \n",
      "2         1  female  58.0                   0      0  26.5500   First   \n",
      "3         1  female  55.0                   0      0  16.0000  Second   \n",
      "4         1    male  34.0                   0      0  13.0000  Second   \n",
      "\n",
      "      deck  embark_town alone  \n",
      "0  unknown  Southampton     y  \n",
      "1        E  Southampton     y  \n",
      "2        C  Southampton     y  \n",
      "3  unknown  Southampton     y  \n",
      "4        D  Southampton     y  \n"
     ]
    }
   ],
   "source": [
    "# 下载数据集\n",
    "train_file = 'data/titanic/train.csv'\n",
    "eval_file = 'data/titanic/eval.csv'\n",
    "\n",
    "train_df = pd.read_csv(train_file)\n",
    "eval_df = pd.read_csv(eval_file)\n",
    "\n",
    "print(train_df.head())\n",
    "print(eval_df.head())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "      sex   age  n_siblings_spouses  parch     fare  class     deck  \\\n",
      "0    male  22.0                   1      0   7.2500  Third  unknown   \n",
      "1  female  38.0                   1      0  71.2833  First        C   \n",
      "2  female  26.0                   0      0   7.9250  Third  unknown   \n",
      "3  female  35.0                   1      0  53.1000  First        C   \n",
      "4    male  28.0                   0      0   8.4583  Third  unknown   \n",
      "\n",
      "   embark_town alone  \n",
      "0  Southampton     n  \n",
      "1    Cherbourg     n  \n",
      "2  Southampton     y  \n",
      "3  Southampton     n  \n",
      "4   Queenstown     y  \n",
      "      sex   age  n_siblings_spouses  parch     fare   class     deck  \\\n",
      "0    male  35.0                   0      0   8.0500   Third  unknown   \n",
      "1    male  54.0                   0      0  51.8625   First        E   \n",
      "2  female  58.0                   0      0  26.5500   First        C   \n",
      "3  female  55.0                   0      0  16.0000  Second  unknown   \n",
      "4    male  34.0                   0      0  13.0000  Second        D   \n",
      "\n",
      "   embark_town alone  \n",
      "0  Southampton     y  \n",
      "1  Southampton     y  \n",
      "2  Southampton     y  \n",
      "3  Southampton     y  \n",
      "4  Southampton     y  \n",
      "0    0\n",
      "1    1\n",
      "2    1\n",
      "3    1\n",
      "4    0\n",
      "Name: survived, dtype: int64\n",
      "0    0\n",
      "1    0\n",
      "2    1\n",
      "3    1\n",
      "4    1\n",
      "Name: survived, dtype: int64\n"
     ]
    }
   ],
   "source": [
    "# 将survived字段取出，赋给label\n",
    "y_train = train_df.pop('survived')\n",
    "y_eval = eval_df.pop('survived')\n",
    "\n",
    "print(train_df.head())\n",
    "print(eval_df.head())\n",
    "print(y_train.head())\n",
    "print(y_eval.head())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>age</th>\n",
       "      <th>n_siblings_spouses</th>\n",
       "      <th>parch</th>\n",
       "      <th>fare</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>count</th>\n",
       "      <td>627.000000</td>\n",
       "      <td>627.000000</td>\n",
       "      <td>627.000000</td>\n",
       "      <td>627.000000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>mean</th>\n",
       "      <td>29.631308</td>\n",
       "      <td>0.545455</td>\n",
       "      <td>0.379585</td>\n",
       "      <td>34.385399</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>std</th>\n",
       "      <td>12.511818</td>\n",
       "      <td>1.151090</td>\n",
       "      <td>0.792999</td>\n",
       "      <td>54.597730</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>min</th>\n",
       "      <td>0.750000</td>\n",
       "      <td>0.000000</td>\n",
       "      <td>0.000000</td>\n",
       "      <td>0.000000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>25%</th>\n",
       "      <td>23.000000</td>\n",
       "      <td>0.000000</td>\n",
       "      <td>0.000000</td>\n",
       "      <td>7.895800</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>50%</th>\n",
       "      <td>28.000000</td>\n",
       "      <td>0.000000</td>\n",
       "      <td>0.000000</td>\n",
       "      <td>15.045800</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>75%</th>\n",
       "      <td>35.000000</td>\n",
       "      <td>1.000000</td>\n",
       "      <td>0.000000</td>\n",
       "      <td>31.387500</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>max</th>\n",
       "      <td>80.000000</td>\n",
       "      <td>8.000000</td>\n",
       "      <td>5.000000</td>\n",
       "      <td>512.329200</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "              age  n_siblings_spouses       parch        fare\n",
       "count  627.000000          627.000000  627.000000  627.000000\n",
       "mean    29.631308            0.545455    0.379585   34.385399\n",
       "std     12.511818            1.151090    0.792999   54.597730\n",
       "min      0.750000            0.000000    0.000000    0.000000\n",
       "25%     23.000000            0.000000    0.000000    7.895800\n",
       "50%     28.000000            0.000000    0.000000   15.045800\n",
       "75%     35.000000            1.000000    0.000000   31.387500\n",
       "max     80.000000            8.000000    5.000000  512.329200"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 查看train中的统计量\n",
    "train_df.describe()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(627, 9) (264, 9)\n"
     ]
    }
   ],
   "source": [
    "# 查看shape大小\n",
    "print(train_df.shape, eval_df.shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<matplotlib.axes._subplots.AxesSubplot at 0x16b488800f0>"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "# 查看年龄分布，用直方图展示\n",
    "train_df.age.hist(bins=20)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<matplotlib.axes._subplots.AxesSubplot at 0x16b4a96ef28>"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAYYAAAD4CAYAAADo30HgAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4xLjIsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy8li6FKAAALhUlEQVR4nO3cbYxm9VnH8d9VFhYDhFpBs4HWKbjRNEBLbdHYhlDTYMuaQtOYNK2VJqTEqFVjiKESGww+YJsafOFDsDYSpZIYa4r0BZJCY1JN21152CWwlsoaC6SkaUoxJNXA3xdzNp1rnBl2YfY+98Lnk0zm3GfO3Oeaf/be75wzs1tjjADAYa+YewAAloswANAIAwCNMADQCAMAzY65B9gOZ5xxxlhZWZl7DIDjyr59+745xjhz/f6XRBhWVlayd+/euccAOK5U1X9utN+tJAAaYQCgEQYAGmEAoBEGABphAKARBgAaYQCgEQYAGmEAoBEGABphAKARBgAaYQCgEQYAGmEAoBEGABphAKARBgAaYQCgEQYAGmEAoBEGABphAKARBgAaYQCg2TH3ANth/2NPZeXaz809Bmzo0I175h4BjoorBgAaYQCgEQYAGmEAoBEGABphAKARBgAaYQCgEQYAGmEAoBEGABphAKARBgAaYQCgEQYAGmEAoBEGABphAKARBgAaYQCgEQYAGmEAoBEGAJrnDUNV/WpVPVRVtx6LAarq+qq65lg8NwBHb8cRHPNLSd45xnj0WA8DwPy2DENV/XmSc5LcXlW3JTk3yfnT510/xvhsVX0wyRVJTkhyXpJPJDkpyQeSfDfJZWOMb1XVh5JcPX3skSQfGGM8s+585yb5kyRnJnkmyYfGGA9v09cKwBHY8lbSGOMXkzye5G1JTkly9xjjzdPjj1fVKdOh5yV5X5KLkvxekmfGGBcm+dckvzAd85kxxpvHGK9P8lCSqzY45c1JPjzG+PEk1yT5081mq6qrq2pvVe199pmnjuyrBeB5HcmtpMMuTfKuNT8PODnJa6bte8YYTyd5uqqeSvKP0/79SS6Yts+rqt9N8sokpya5c+2TV9WpSX4qyd9V1eHdOzcbZoxxc1ZDkp27do+j+DoA2MLRhKGSvGeMcbDtrPqJrN4yOuy5NY+fW3OOv0pyxRjj/un20yXrnv8VSb49xnjDUcwEwDY7ml9XvTPJh2v6dr6qLjzKc52W5ImqOjHJ+9d/cIzxnSSPVtXPTc9fVfX6ozwHAC/S0YThhiQnJnmgqg5Mj4/Gbyf5UpK7kmz2A+X3J7mqqu5P8mCSy4/yHAC8SDXG8X97fueu3WPXlTfNPQZs6NCNe+YeATZUVfvGGG9av9+/fAagEQYAGmEAoBEGABphAKARBgAaYQCgEQYAGmEAoBEGABphAKARBgAaYQCgEQYAGmEAoBEGABphAKARBgAaYQCgEQYAGmEAoNkx9wDb4fyzTs/eG/fMPQbAS4IrBgAaYQCgEQYAGmEAoBEGABphAKARBgAaYQCgEQYAGmEAoBEGABphAKARBgAaYQCgEQYAGmEAoBEGABphAKARBgAaYQCgEQYAGmEAoBEGABphAKARBgAaYQCgEQYAGmEAoBEGABphAKARBgAaYQCgEQYAGmEAoBEGABphAKARBgAaYQCgEQYAGmEAoBEGABphAKARBgAaYQCgEQYAGmEAoBEGABphAKARBgAaYQCgEQYAGmEAoBEGAJodcw+wHfY/9lRWrv3c3GMALNShG/cck+d1xQBAIwwANMIAQCMMADTCAEAjDAA0wgBAIwwANMIAQCMMADTCAEAjDAA0wgBAIwwANMIAQCMMADTCAEAjDAA0wgBAIwwANMIAQCMMADTCAECzFGGoqkuq6o655wBgScIAwPLYtjBU1UpVPVxVn6yqA1V1a1W9vaq+WFVfraqLprd/qap7p/c/usHznFJVn6qqr0zHXb5dMwLw/Lb7iuFHkvxxkguS/FiS9yV5a5JrkvxWkoeTXDzGuDDJR5P8/gbPcV2Su8cYb07ytiQfr6pT1h9UVVdX1d6q2vvsM09t85cB8PK1Y5uf79Exxv4kqaoHk3x+jDGqan+SlSSnJ7mlqnYnGUlO3OA5Lk3yrqq6Znp8cpLXJHlo7UFjjJuT3JwkO3ftHtv8dQC8bG13GL67Zvu5NY+fm851Q5J7xhjvrqqVJF/Y4DkqyXvGGAe3eTYAjsCif/h8epLHpu0PbnLMnUk+XFWVJFV14QLmAmCy6DB8LMkfVNUXk5ywyTE3ZPUW0wNVdWB6DMCC1BjH/+35nbt2j11X3jT3GAALdejGPS/q86tq3xjjTev3+3cMADTCAEAjDAA0wgBAIwwANMIAQCMMADTCAEAjDAA0wgBAIwwANMIAQCMMADTCAEAjDAA0wgBAIwwANMIAQCMMADTCAEAjDAA0wgBAs2PuAbbD+Wednr037pl7DICXBFcMADTCAEAjDAA0wgBAIwwANMIAQCMMADTCAEAjDAA0wgBAIwwANMIAQCMMADTCAEAjDAA0wgBAIwwANMIAQCMMADTCAEAjDAA0wgBAIwwANMIAQCMMADTCAEBTY4y5Z3jRqurpJAfnnmMTZyT55txDbGBZ50rM9kKZ7YV5Oc/2w2OMM9fv3HEMT7hIB8cYb5p7iI1U1d5lnG1Z50rM9kKZ7YUx2//nVhIAjTAA0LxUwnDz3ANsYVlnW9a5ErO9UGZ7Ycy2zkvih88AbJ+XyhUDANtEGABojuswVNU7qupgVT1SVdcuwTyHqmp/Vd1XVXunfa+qqruq6qvT++9f0Cyfqqonq+rAmn2bzlJVH5nW8WBV/cwMs11fVY9Na3dfVV226Nmq6tVVdU9VPVRVD1bVr037Z1+3LWZbhnU7uaq+XFX3T7P9zrR/GdZts9lmX7c15zuhqu6tqjumx7OvW8YYx+VbkhOSfC3JOUlOSnJ/ktfNPNOhJGes2/exJNdO29cm+cMFzXJxkjcmOfB8syR53bR+O5O8dlrXExY82/VJrtng2IXNlmRXkjdO26cl+ffp/LOv2xazLcO6VZJTp+0Tk3wpyU8uybptNtvs67bmnL+R5NNJ7pgez75ux/MVw0VJHhlj/McY43+S3Jbk8pln2sjlSW6Ztm9JcsUiTjrG+Ock3zrCWS5PctsY47tjjEeTPJLV9V3kbJtZ2GxjjCfGGP82bT+d5KEkZ2UJ1m2L2TazyNnGGOO/p4cnTm8jy7Fum822mYW+Fqrq7CR7knxy3QyzrtvxHIazkvzXmsdfz9YvlEUYSf6pqvZV1dXTvh8aYzyRrL64k/zgbNNtPsuyrOWvVNUD062mw5fPs8xWVStJLszqd5hLtW7rZkuWYN2m2yH3JXkyyV1jjKVZt01mS5Zg3ZLclOQ3kzy3Zt/s63Y8h6E22Df3796+ZYzxxiTvTPLLVXXxzPMcqWVYyz9Lcm6SNyR5Isknpv0Ln62qTk3y90l+fYzxna0O3WDfomdbinUbYzw7xnhDkrOTXFRV521x+DLMNvu6VdXPJnlyjLHvSD9lg33HZLbjOQxfT/LqNY/PTvL4TLMkScYYj0/vn0zyD1m9zPtGVe1Kkun9k/NNuOkss6/lGOMb0wv4uSR/ke9dIi90tqo6Mat/8d46xvjMtHsp1m2j2ZZl3Q4bY3w7yReSvCNLsm4bzbYk6/aWJO+qqkNZvRX+01X1N1mCdTuew/CVJLur6rVVdVKS9ya5fa5hquqUqjrt8HaSS5McmGa6cjrsyiSfnWfCZItZbk/y3qraWVWvTbI7yZcXOdjhF8Lk3Vldu4XOVlWV5C+TPDTG+KM1H5p93TabbUnW7cyqeuW0/X1J3p7k4SzHum042zKs2xjjI2OMs8cYK1n9++vuMcbPZwnW7Zj9pH0Rb0kuy+pvZ3wtyXUzz3JOVn9j4P4kDx6eJ8kPJPl8kq9O71+1oHn+NquXyP+b1e80rtpqliTXTet4MMk7Z5jtr5PsT/JAVl8AuxY9W5K3ZvXS/IEk901vly3Dum0x2zKs2wVJ7p1mOJDko8/3Z38JZpt93dbNeUm+91tJs6+b/xIDgOZ4vpUEwDEgDAA0wgBAIwwANMIAQCMMADTCAEDzf0WdIOqrm0/iAAAAAElFTkSuQmCC\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "# 查看性别统计，用横向柱状图表示\n",
    "train_df.sex.value_counts().plot(kind = 'barh')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<matplotlib.axes._subplots.AxesSubplot at 0x16b4a9b4160>"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "# 查看不同舱位统计，用横向柱状图表示\n",
    "train_df['class'].value_counts().plot(kind = 'barh')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "sex\n",
      "female    0.778802\n",
      "male      0.180488\n",
      "Name: survived, dtype: float64\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "<matplotlib.axes._subplots.AxesSubplot at 0x16b4aa99128>"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "# 统计男性获救占比和女性获救占比\n",
    "print(pd.concat([train_df, y_train], axis=1).groupby('sex').survived.mean())\n",
    "pd.concat([train_df, y_train], axis=1).groupby('sex').survived.mean().plot(kind='barh')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### feature_column 做特征工程\n",
    "feature_column对列数据进行封装，如果列数据是离散值，方便做onehot编码，变成向量，如果列数据是连续值，可以直接输入给模型，也可以对数据进行分桶变成离散值，再做onehot编码"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "sex ['male' 'female']\n",
      "n_siblings_spouses [1 0 3 4 2 5 8]\n",
      "parch [0 1 2 5 3 4]\n",
      "class ['Third' 'First' 'Second']\n",
      "deck ['unknown' 'C' 'G' 'A' 'B' 'D' 'F' 'E']\n",
      "embark_town ['Southampton' 'Cherbourg' 'Queenstown' 'unknown']\n",
      "alone ['n' 'y']\n"
     ]
    }
   ],
   "source": [
    "# 将数据分成两类：离散和连续\n",
    "categorical_columns = ['sex', 'n_siblings_spouses', 'parch', 'class',\n",
    "                       'deck', 'embark_town', 'alone']\n",
    "numeric_columns = ['age', 'fare']\n",
    "\n",
    "feature_columns = []\n",
    "for categorical_column in categorical_columns:\n",
    "    # 获取离散值所有可能值\n",
    "    vocab = train_df[categorical_column].unique()\n",
    "    print(categorical_column, vocab)\n",
    "    # 对离散值封装，做onehot编码，再加入feature_columns中\n",
    "    feature_columns.append(\n",
    "        tf.feature_column.indicator_column(\n",
    "            tf.feature_column.categorical_column_with_vocabulary_list(\n",
    "                categorical_column, vocab)))\n",
    "    \n",
    "for numeric_column in numeric_columns:\n",
    "    feature_columns.append(\n",
    "        tf.feature_column.numeric_column(numeric_column, dtype=tf.float32))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'sex': 0        male\n",
       " 1      female\n",
       " 2      female\n",
       " 3      female\n",
       " 4        male\n",
       "         ...  \n",
       " 622      male\n",
       " 623      male\n",
       " 624    female\n",
       " 625    female\n",
       " 626      male\n",
       " Name: sex, Length: 627, dtype: object, 'age': 0      22.0\n",
       " 1      38.0\n",
       " 2      26.0\n",
       " 3      35.0\n",
       " 4      28.0\n",
       "        ... \n",
       " 622    28.0\n",
       " 623    25.0\n",
       " 624    19.0\n",
       " 625    28.0\n",
       " 626    32.0\n",
       " Name: age, Length: 627, dtype: float64, 'n_siblings_spouses': 0      1\n",
       " 1      1\n",
       " 2      0\n",
       " 3      1\n",
       " 4      0\n",
       "       ..\n",
       " 622    0\n",
       " 623    0\n",
       " 624    0\n",
       " 625    1\n",
       " 626    0\n",
       " Name: n_siblings_spouses, Length: 627, dtype: int64, 'parch': 0      0\n",
       " 1      0\n",
       " 2      0\n",
       " 3      0\n",
       " 4      0\n",
       "       ..\n",
       " 622    0\n",
       " 623    0\n",
       " 624    0\n",
       " 625    2\n",
       " 626    0\n",
       " Name: parch, Length: 627, dtype: int64, 'fare': 0       7.2500\n",
       " 1      71.2833\n",
       " 2       7.9250\n",
       " 3      53.1000\n",
       " 4       8.4583\n",
       "         ...   \n",
       " 622    10.5000\n",
       " 623     7.0500\n",
       " 624    30.0000\n",
       " 625    23.4500\n",
       " 626     7.7500\n",
       " Name: fare, Length: 627, dtype: float64, 'class': 0       Third\n",
       " 1       First\n",
       " 2       Third\n",
       " 3       First\n",
       " 4       Third\n",
       "         ...  \n",
       " 622    Second\n",
       " 623     Third\n",
       " 624     First\n",
       " 625     Third\n",
       " 626     Third\n",
       " Name: class, Length: 627, dtype: object, 'deck': 0      unknown\n",
       " 1            C\n",
       " 2      unknown\n",
       " 3            C\n",
       " 4      unknown\n",
       "         ...   \n",
       " 622    unknown\n",
       " 623    unknown\n",
       " 624          B\n",
       " 625    unknown\n",
       " 626    unknown\n",
       " Name: deck, Length: 627, dtype: object, 'embark_town': 0      Southampton\n",
       " 1        Cherbourg\n",
       " 2      Southampton\n",
       " 3      Southampton\n",
       " 4       Queenstown\n",
       "           ...     \n",
       " 622    Southampton\n",
       " 623    Southampton\n",
       " 624    Southampton\n",
       " 625    Southampton\n",
       " 626     Queenstown\n",
       " Name: embark_town, Length: 627, dtype: object, 'alone': 0      n\n",
       " 1      n\n",
       " 2      y\n",
       " 3      n\n",
       " 4      y\n",
       "       ..\n",
       " 622    y\n",
       " 623    y\n",
       " 624    y\n",
       " 625    n\n",
       " 626    y\n",
       " Name: alone, Length: 627, dtype: object}"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 把dataframe变成字典\n",
    "dict(train_df)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 从pandas dataframe中构建dataset\n",
    "def make_dataset(data_df, label_df, epochs = 10, shuffle = True, batch_size = 32):\n",
    "    dataset = tf.data.Dataset.from_tensor_slices((dict(data_df), label_df))\n",
    "    if shuffle:\n",
    "        dataset = dataset.shuffle(10000)\n",
    "    dataset = dataset.repeat(epochs).batch(batch_size)\n",
    "    return dataset"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'sex': <tf.Tensor: id=38, shape=(5,), dtype=string, numpy=array([b'male', b'female', b'male', b'male', b'male'], dtype=object)>, 'age': <tf.Tensor: id=30, shape=(5,), dtype=float64, numpy=array([32., 28., 31., 28., 28.])>, 'n_siblings_spouses': <tf.Tensor: id=36, shape=(5,), dtype=int32, numpy=array([0, 3, 0, 0, 0])>, 'parch': <tf.Tensor: id=37, shape=(5,), dtype=int32, numpy=array([0, 1, 0, 0, 0])>, 'fare': <tf.Tensor: id=35, shape=(5,), dtype=float64, numpy=array([ 7.8542, 25.4667, 13.    ,  7.75  , 26.    ])>, 'class': <tf.Tensor: id=32, shape=(5,), dtype=string, numpy=array([b'Third', b'Third', b'Second', b'Third', b'First'], dtype=object)>, 'deck': <tf.Tensor: id=33, shape=(5,), dtype=string, numpy=array([b'unknown', b'unknown', b'unknown', b'unknown', b'A'], dtype=object)>, 'embark_town': <tf.Tensor: id=34, shape=(5,), dtype=string, numpy=\n",
      "array([b'Southampton', b'Southampton', b'Southampton', b'Queenstown',\n",
      "       b'Southampton'], dtype=object)>, 'alone': <tf.Tensor: id=31, shape=(5,), dtype=string, numpy=array([b'y', b'n', b'y', b'y', b'y'], dtype=object)>} tf.Tensor([1 0 1 0 0], shape=(5,), dtype=int32)\n"
     ]
    }
   ],
   "source": [
    "# test\n",
    "train_dataset = make_dataset(train_df, y_train, batch_size=5)\n",
    "for x, y in train_dataset.take(1):\n",
    "    print(x, y)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "将 feature_columns 应用到 dataset上\n",
    "\n",
    "feature_columns 是对feature变化的一组规则，keras.layers.DenseFeatures可以将每一个规则应用到dataset上去"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "WARNING:tensorflow:Layer dense_features is casting an input tensor from dtype float64 to the layer's dtype of float32, which is new behavior in TensorFlow 2.  The layer has dtype float32 because it's dtype defaults to floatx.\n",
      "\n",
      "If you intended to run this layer in float32, you can safely ignore this warning. If in doubt, this warning is likely only an issue if you are porting a TensorFlow 1.X model to TensorFlow 2.\n",
      "\n",
      "To change all layers to have dtype float64 by default, call `tf.keras.backend.set_floatx('float64')`. To change just this layer, pass dtype='float64' to the layer constructor. If you are the author of this layer, you can disable autocasting by passing autocast=False to the base Layer constructor.\n",
      "\n",
      "[[18.]\n",
      " [31.]\n",
      " [28.]\n",
      " [28.]\n",
      " [31.]]\n",
      "WARNING:tensorflow:Layer dense_features_1 is casting an input tensor from dtype float64 to the layer's dtype of float32, which is new behavior in TensorFlow 2.  The layer has dtype float32 because it's dtype defaults to floatx.\n",
      "\n",
      "If you intended to run this layer in float32, you can safely ignore this warning. If in doubt, this warning is likely only an issue if you are porting a TensorFlow 1.X model to TensorFlow 2.\n",
      "\n",
      "To change all layers to have dtype float64 by default, call `tf.keras.backend.set_floatx('float64')`. To change just this layer, pass dtype='float64' to the layer constructor. If you are the author of this layer, you can disable autocasting by passing autocast=False to the base Layer constructor.\n",
      "\n",
      "WARNING:tensorflow:From f:\\condaenv\\tf2_py36\\lib\\site-packages\\tensorflow_core\\python\\feature_column\\feature_column_v2.py:4276: IndicatorColumn._variable_shape (from tensorflow.python.feature_column.feature_column_v2) is deprecated and will be removed in a future version.\n",
      "Instructions for updating:\n",
      "The old _FeatureColumn APIs are being deprecated. Please use the new FeatureColumn APIs instead.\n",
      "WARNING:tensorflow:From f:\\condaenv\\tf2_py36\\lib\\site-packages\\tensorflow_core\\python\\feature_column\\feature_column_v2.py:4331: VocabularyListCategoricalColumn._num_buckets (from tensorflow.python.feature_column.feature_column_v2) is deprecated and will be removed in a future version.\n",
      "Instructions for updating:\n",
      "The old _FeatureColumn APIs are being deprecated. Please use the new FeatureColumn APIs instead.\n",
      "[[1. 0.]\n",
      " [0. 1.]\n",
      " [1. 0.]\n",
      " [0. 1.]\n",
      " [1. 0.]]\n"
     ]
    }
   ],
   "source": [
    "# keras.layers.DenseFeatures test\n",
    "for x, y in train_dataset.take(1):\n",
    "    age_column = feature_columns[7]\n",
    "    gender_column = feature_columns[0]\n",
    "    print(keras.layers.DenseFeatures(age_column)(x).numpy())\n",
    "    print(keras.layers.DenseFeatures(gender_column)(x).numpy())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "WARNING:tensorflow:Layer dense_features_2 is casting an input tensor from dtype float64 to the layer's dtype of float32, which is new behavior in TensorFlow 2.  The layer has dtype float32 because it's dtype defaults to floatx.\n",
      "\n",
      "If you intended to run this layer in float32, you can safely ignore this warning. If in doubt, this warning is likely only an issue if you are porting a TensorFlow 1.X model to TensorFlow 2.\n",
      "\n",
      "To change all layers to have dtype float64 by default, call `tf.keras.backend.set_floatx('float64')`. To change just this layer, pass dtype='float64' to the layer constructor. If you are the author of this layer, you can disable autocasting by passing autocast=False to the base Layer constructor.\n",
      "\n",
      "[[21.      0.      1.      0.      1.      0.      0.      0.      0.\n",
      "   0.      0.      1.      0.      0.      1.      0.      0.      0.\n",
      "  77.9583  0.      1.      0.      0.      0.      0.      0.      1.\n",
      "   0.      0.      0.      0.      0.      0.      1.    ]\n",
      " [25.      1.      0.      1.      0.      0.      1.      0.      0.\n",
      "   0.      0.      0.      0.      0.      1.      0.      0.      0.\n",
      "  17.8     1.      0.      0.      0.      0.      0.      0.      1.\n",
      "   0.      0.      0.      0.      0.      1.      0.    ]\n",
      " [26.      1.      0.      0.      0.      1.      1.      0.      0.\n",
      "   0.      0.      0.      0.      0.      1.      0.      0.      0.\n",
      "  26.      1.      0.      0.      0.      0.      0.      0.      0.\n",
      "   1.      0.      0.      0.      0.      0.      1.    ]\n",
      " [22.      0.      1.      1.      0.      0.      1.      0.      0.\n",
      "   0.      0.      0.      0.      0.      1.      0.      0.      0.\n",
      "   9.35    0.      1.      0.      0.      0.      0.      0.      1.\n",
      "   0.      0.      0.      0.      0.      1.      0.    ]\n",
      " [19.      0.      1.      1.      0.      0.      0.      0.      0.\n",
      "   0.      0.      0.      1.      0.      1.      0.      0.      0.\n",
      "   7.65    0.      1.      0.      0.      0.      0.      0.      1.\n",
      "   0.      0.      0.      0.      0.      1.      0.    ]]\n"
     ]
    }
   ],
   "source": [
    "# 将feature_columns 全部应用\n",
    "for x, y in train_dataset.take(1):\n",
    "    print(keras.layers.DenseFeatures(feature_columns)(x).numpy())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### keras建模"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [],
   "source": [
    "model = keras.models.Sequential([\n",
    "    keras.layers.DenseFeatures(feature_columns),\n",
    "    keras.layers.Dense(100, activation='relu'),\n",
    "    keras.layers.Dense(100, activation='relu'),\n",
    "    keras.layers.Dense(2, activation='softmax'),\n",
    "])\n",
    "model.compile(loss='sparse_categorical_crossentropy',\n",
    "              optimizer=keras.optimizers.Adam(lr=0.01),\n",
    "              metrics=['accuracy'])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "model 训练有两种方式：\n",
    "1. model.fit\n",
    "2. model -> estimator -> train"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "WARNING:tensorflow:Layer sequential is casting an input tensor from dtype float64 to the layer's dtype of float32, which is new behavior in TensorFlow 2.  The layer has dtype float32 because it's dtype defaults to floatx.\n",
      "\n",
      "If you intended to run this layer in float32, you can safely ignore this warning. If in doubt, this warning is likely only an issue if you are porting a TensorFlow 1.X model to TensorFlow 2.\n",
      "\n",
      "To change all layers to have dtype float64 by default, call `tf.keras.backend.set_floatx('float64')`. To change just this layer, pass dtype='float64' to the layer constructor. If you are the author of this layer, you can disable autocasting by passing autocast=False to the base Layer constructor.\n",
      "\n",
      "Train for 18 steps, validate for 8 steps\n",
      "Epoch 1/100\n",
      "18/18 [==============================] - 2s 96ms/step - loss: 2.5666 - accuracy: 0.5885 - val_loss: 0.9956 - val_accuracy: 0.5391\n",
      "Epoch 2/100\n",
      "18/18 [==============================] - 0s 11ms/step - loss: 0.6496 - accuracy: 0.6927 - val_loss: 0.5810 - val_accuracy: 0.6797\n",
      "Epoch 3/100\n",
      "18/18 [==============================] - 0s 11ms/step - loss: 0.6007 - accuracy: 0.6962 - val_loss: 0.5490 - val_accuracy: 0.7305\n",
      "Epoch 4/100\n",
      "18/18 [==============================] - 0s 10ms/step - loss: 0.6100 - accuracy: 0.7413 - val_loss: 0.5448 - val_accuracy: 0.7266\n",
      "Epoch 5/100\n",
      "18/18 [==============================] - 0s 11ms/step - loss: 0.5088 - accuracy: 0.7378 - val_loss: 0.4989 - val_accuracy: 0.7422\n",
      "Epoch 6/100\n",
      "18/18 [==============================] - 0s 11ms/step - loss: 0.5133 - accuracy: 0.7448 - val_loss: 0.5290 - val_accuracy: 0.7383\n",
      "Epoch 7/100\n",
      "18/18 [==============================] - 0s 10ms/step - loss: 0.4786 - accuracy: 0.8090 - val_loss: 0.5099 - val_accuracy: 0.7383\n",
      "Epoch 8/100\n",
      "18/18 [==============================] - 0s 11ms/step - loss: 0.5299 - accuracy: 0.7500 - val_loss: 0.5332 - val_accuracy: 0.7344\n",
      "Epoch 9/100\n",
      "18/18 [==============================] - 0s 11ms/step - loss: 0.4400 - accuracy: 0.8247 - val_loss: 0.4670 - val_accuracy: 0.7578\n",
      "Epoch 10/100\n",
      "18/18 [==============================] - 0s 11ms/step - loss: 0.4429 - accuracy: 0.8142 - val_loss: 0.4577 - val_accuracy: 0.7539\n",
      "Epoch 11/100\n",
      "18/18 [==============================] - 0s 11ms/step - loss: 0.4457 - accuracy: 0.8212 - val_loss: 0.4587 - val_accuracy: 0.7734\n",
      "Epoch 12/100\n",
      "18/18 [==============================] - 0s 11ms/step - loss: 0.4347 - accuracy: 0.8177 - val_loss: 0.4600 - val_accuracy: 0.7734\n",
      "Epoch 13/100\n",
      "18/18 [==============================] - 0s 11ms/step - loss: 0.4146 - accuracy: 0.8177 - val_loss: 0.4504 - val_accuracy: 0.7656\n",
      "Epoch 14/100\n",
      "18/18 [==============================] - 0s 11ms/step - loss: 0.4020 - accuracy: 0.8403 - val_loss: 0.4766 - val_accuracy: 0.7773\n",
      "Epoch 15/100\n",
      "18/18 [==============================] - 0s 11ms/step - loss: 0.4450 - accuracy: 0.8056 - val_loss: 0.4924 - val_accuracy: 0.7500\n",
      "Epoch 16/100\n",
      "18/18 [==============================] - 0s 11ms/step - loss: 0.4615 - accuracy: 0.8056 - val_loss: 0.4975 - val_accuracy: 0.7695\n",
      "Epoch 17/100\n",
      "18/18 [==============================] - 0s 11ms/step - loss: 0.4188 - accuracy: 0.8299 - val_loss: 0.4905 - val_accuracy: 0.7695\n",
      "Epoch 18/100\n",
      "18/18 [==============================] - 0s 11ms/step - loss: 0.4255 - accuracy: 0.8247 - val_loss: 0.4651 - val_accuracy: 0.7852\n",
      "Epoch 19/100\n",
      "18/18 [==============================] - 0s 11ms/step - loss: 0.3958 - accuracy: 0.8420 - val_loss: 0.4662 - val_accuracy: 0.7734\n",
      "Epoch 20/100\n",
      "18/18 [==============================] - 0s 11ms/step - loss: 0.4534 - accuracy: 0.7951 - val_loss: 0.4601 - val_accuracy: 0.7734\n",
      "Epoch 21/100\n",
      "18/18 [==============================] - 0s 11ms/step - loss: 0.4326 - accuracy: 0.8090 - val_loss: 0.4707 - val_accuracy: 0.7852\n",
      "Epoch 22/100\n",
      "18/18 [==============================] - 0s 12ms/step - loss: 0.4120 - accuracy: 0.8490 - val_loss: 0.4532 - val_accuracy: 0.7812\n",
      "Epoch 23/100\n",
      "18/18 [==============================] - 0s 12ms/step - loss: 0.4127 - accuracy: 0.8281 - val_loss: 0.4514 - val_accuracy: 0.7734\n",
      "Epoch 24/100\n",
      "18/18 [==============================] - 0s 12ms/step - loss: 0.3898 - accuracy: 0.8229 - val_loss: 0.4542 - val_accuracy: 0.7812\n",
      "Epoch 25/100\n",
      "18/18 [==============================] - 0s 11ms/step - loss: 0.4286 - accuracy: 0.8003 - val_loss: 0.4528 - val_accuracy: 0.7930\n",
      "Epoch 26/100\n",
      "18/18 [==============================] - 0s 12ms/step - loss: 0.4196 - accuracy: 0.8299 - val_loss: 0.4570 - val_accuracy: 0.8008\n",
      "Epoch 27/100\n",
      "18/18 [==============================] - 0s 12ms/step - loss: 0.3906 - accuracy: 0.8333 - val_loss: 0.4541 - val_accuracy: 0.7930\n",
      "Epoch 28/100\n",
      "18/18 [==============================] - 0s 11ms/step - loss: 0.3727 - accuracy: 0.8420 - val_loss: 0.4614 - val_accuracy: 0.8125\n",
      "Epoch 29/100\n",
      "18/18 [==============================] - 0s 11ms/step - loss: 0.4666 - accuracy: 0.8125 - val_loss: 0.4619 - val_accuracy: 0.7734\n",
      "Epoch 30/100\n",
      "18/18 [==============================] - 0s 11ms/step - loss: 0.4713 - accuracy: 0.7830 - val_loss: 0.4610 - val_accuracy: 0.7891\n",
      "Epoch 31/100\n",
      "18/18 [==============================] - 0s 11ms/step - loss: 0.4006 - accuracy: 0.8299 - val_loss: 0.4779 - val_accuracy: 0.7812\n",
      "Epoch 32/100\n",
      "18/18 [==============================] - 0s 11ms/step - loss: 0.3801 - accuracy: 0.8333 - val_loss: 0.4624 - val_accuracy: 0.7773\n",
      "Epoch 33/100\n",
      "18/18 [==============================] - 0s 11ms/step - loss: 0.3887 - accuracy: 0.8385 - val_loss: 0.4477 - val_accuracy: 0.8047\n",
      "Epoch 34/100\n",
      "18/18 [==============================] - 0s 11ms/step - loss: 0.4188 - accuracy: 0.8056 - val_loss: 0.4861 - val_accuracy: 0.7656\n",
      "Epoch 35/100\n",
      "18/18 [==============================] - 0s 10ms/step - loss: 0.3845 - accuracy: 0.8299 - val_loss: 0.4525 - val_accuracy: 0.7891\n",
      "Epoch 36/100\n",
      "18/18 [==============================] - 0s 11ms/step - loss: 0.3742 - accuracy: 0.8385 - val_loss: 0.4590 - val_accuracy: 0.7891\n",
      "Epoch 37/100\n",
      "18/18 [==============================] - 0s 10ms/step - loss: 0.3910 - accuracy: 0.8316 - val_loss: 0.4761 - val_accuracy: 0.7812\n",
      "Epoch 38/100\n",
      "18/18 [==============================] - 0s 11ms/step - loss: 0.3587 - accuracy: 0.8542 - val_loss: 0.4513 - val_accuracy: 0.8125\n",
      "Epoch 39/100\n",
      "18/18 [==============================] - 0s 10ms/step - loss: 0.3531 - accuracy: 0.8490 - val_loss: 0.4668 - val_accuracy: 0.7969\n",
      "Epoch 40/100\n",
      "18/18 [==============================] - 0s 11ms/step - loss: 0.3986 - accuracy: 0.8316 - val_loss: 0.4454 - val_accuracy: 0.7891\n",
      "Epoch 41/100\n",
      "18/18 [==============================] - 0s 10ms/step - loss: 0.3829 - accuracy: 0.8351 - val_loss: 0.4856 - val_accuracy: 0.7852\n",
      "Epoch 42/100\n",
      "18/18 [==============================] - 0s 10ms/step - loss: 0.3636 - accuracy: 0.8455 - val_loss: 0.4678 - val_accuracy: 0.7969\n",
      "Epoch 43/100\n",
      "18/18 [==============================] - 0s 11ms/step - loss: 0.3544 - accuracy: 0.8524 - val_loss: 0.4800 - val_accuracy: 0.8008\n",
      "Epoch 44/100\n",
      "18/18 [==============================] - 0s 10ms/step - loss: 0.3464 - accuracy: 0.8542 - val_loss: 0.4659 - val_accuracy: 0.7891\n",
      "Epoch 45/100\n",
      "18/18 [==============================] - 0s 10ms/step - loss: 0.3613 - accuracy: 0.8385 - val_loss: 0.4823 - val_accuracy: 0.8086\n",
      "Epoch 46/100\n",
      "18/18 [==============================] - 0s 11ms/step - loss: 0.3876 - accuracy: 0.8194 - val_loss: 0.4580 - val_accuracy: 0.8047\n",
      "Epoch 47/100\n",
      "18/18 [==============================] - 0s 10ms/step - loss: 0.3648 - accuracy: 0.8385 - val_loss: 0.4865 - val_accuracy: 0.7969\n",
      "Epoch 48/100\n",
      "18/18 [==============================] - 0s 11ms/step - loss: 0.3753 - accuracy: 0.8247 - val_loss: 0.4540 - val_accuracy: 0.7773\n",
      "Epoch 49/100\n",
      "18/18 [==============================] - 0s 10ms/step - loss: 0.3637 - accuracy: 0.8420 - val_loss: 0.4435 - val_accuracy: 0.7969\n",
      "Epoch 50/100\n",
      "18/18 [==============================] - 0s 10ms/step - loss: 0.3697 - accuracy: 0.8333 - val_loss: 0.4571 - val_accuracy: 0.7969\n",
      "Epoch 51/100\n",
      "18/18 [==============================] - 0s 10ms/step - loss: 0.3479 - accuracy: 0.8403 - val_loss: 0.4422 - val_accuracy: 0.8164\n",
      "Epoch 52/100\n",
      "18/18 [==============================] - 0s 10ms/step - loss: 0.3446 - accuracy: 0.8559 - val_loss: 0.4503 - val_accuracy: 0.8125\n",
      "Epoch 53/100\n",
      "18/18 [==============================] - 0s 10ms/step - loss: 0.3151 - accuracy: 0.8628 - val_loss: 0.5007 - val_accuracy: 0.8125\n",
      "Epoch 54/100\n",
      "18/18 [==============================] - 0s 10ms/step - loss: 0.4065 - accuracy: 0.8299 - val_loss: 0.4468 - val_accuracy: 0.8047\n",
      "Epoch 55/100\n",
      "18/18 [==============================] - 0s 10ms/step - loss: 0.3586 - accuracy: 0.8438 - val_loss: 0.4639 - val_accuracy: 0.7969\n",
      "Epoch 56/100\n",
      "18/18 [==============================] - 0s 11ms/step - loss: 0.3871 - accuracy: 0.8351 - val_loss: 0.4281 - val_accuracy: 0.8125\n",
      "Epoch 57/100\n",
      "18/18 [==============================] - 0s 10ms/step - loss: 0.3484 - accuracy: 0.8455 - val_loss: 0.4644 - val_accuracy: 0.8047\n",
      "Epoch 58/100\n",
      "18/18 [==============================] - 0s 10ms/step - loss: 0.3484 - accuracy: 0.8420 - val_loss: 0.4801 - val_accuracy: 0.7969\n",
      "Epoch 59/100\n",
      "18/18 [==============================] - 0s 11ms/step - loss: 0.3589 - accuracy: 0.8438 - val_loss: 0.4584 - val_accuracy: 0.7930\n",
      "Epoch 60/100\n",
      "18/18 [==============================] - 0s 10ms/step - loss: 0.3513 - accuracy: 0.8455 - val_loss: 0.4391 - val_accuracy: 0.8047\n",
      "Epoch 61/100\n",
      "18/18 [==============================] - 0s 10ms/step - loss: 0.3266 - accuracy: 0.8663 - val_loss: 0.4766 - val_accuracy: 0.8125\n",
      "Epoch 62/100\n",
      "18/18 [==============================] - 0s 10ms/step - loss: 0.3628 - accuracy: 0.8385 - val_loss: 0.4890 - val_accuracy: 0.7812\n",
      "Epoch 63/100\n",
      "18/18 [==============================] - 0s 10ms/step - loss: 0.3751 - accuracy: 0.8316 - val_loss: 0.4493 - val_accuracy: 0.8164\n",
      "Epoch 64/100\n",
      "18/18 [==============================] - 0s 10ms/step - loss: 0.3304 - accuracy: 0.8507 - val_loss: 0.4858 - val_accuracy: 0.8203\n",
      "Epoch 65/100\n",
      "18/18 [==============================] - 0s 11ms/step - loss: 0.3365 - accuracy: 0.8542 - val_loss: 0.4898 - val_accuracy: 0.8047\n",
      "Epoch 66/100\n",
      "18/18 [==============================] - ETA: 0s - loss: 0.3552 - accuracy: 0.84 - 0s 10ms/step - loss: 0.3491 - accuracy: 0.8455 - val_loss: 0.5020 - val_accuracy: 0.7852\n",
      "Epoch 67/100\n",
      "18/18 [==============================] - 0s 10ms/step - loss: 0.3557 - accuracy: 0.8576 - val_loss: 0.4855 - val_accuracy: 0.7773\n",
      "Epoch 68/100\n",
      "18/18 [==============================] - 0s 10ms/step - loss: 0.3200 - accuracy: 0.8542 - val_loss: 0.4766 - val_accuracy: 0.7891\n",
      "Epoch 69/100\n",
      "18/18 [==============================] - 0s 10ms/step - loss: 0.3173 - accuracy: 0.8576 - val_loss: 0.4627 - val_accuracy: 0.8008\n",
      "Epoch 70/100\n",
      "18/18 [==============================] - 0s 10ms/step - loss: 0.3073 - accuracy: 0.8715 - val_loss: 0.4812 - val_accuracy: 0.7891\n",
      "Epoch 71/100\n",
      "18/18 [==============================] - 0s 10ms/step - loss: 0.3437 - accuracy: 0.8628 - val_loss: 0.4885 - val_accuracy: 0.7969\n",
      "Epoch 72/100\n",
      "18/18 [==============================] - 0s 10ms/step - loss: 0.2931 - accuracy: 0.8750 - val_loss: 0.4864 - val_accuracy: 0.7930\n",
      "Epoch 73/100\n",
      "18/18 [==============================] - 0s 10ms/step - loss: 0.3158 - accuracy: 0.8594 - val_loss: 0.4896 - val_accuracy: 0.7969\n",
      "Epoch 74/100\n",
      "18/18 [==============================] - 0s 10ms/step - loss: 0.3396 - accuracy: 0.8507 - val_loss: 0.4787 - val_accuracy: 0.8008\n",
      "Epoch 75/100\n",
      "18/18 [==============================] - 0s 10ms/step - loss: 0.3180 - accuracy: 0.8594 - val_loss: 0.4973 - val_accuracy: 0.7969\n",
      "Epoch 76/100\n",
      "18/18 [==============================] - 0s 10ms/step - loss: 0.3286 - accuracy: 0.8524 - val_loss: 0.4835 - val_accuracy: 0.7852\n",
      "Epoch 77/100\n",
      "18/18 [==============================] - 0s 10ms/step - loss: 0.3206 - accuracy: 0.8559 - val_loss: 0.4885 - val_accuracy: 0.8086\n",
      "Epoch 78/100\n",
      "18/18 [==============================] - 0s 10ms/step - loss: 0.3468 - accuracy: 0.8490 - val_loss: 0.5091 - val_accuracy: 0.7969\n",
      "Epoch 79/100\n",
      "18/18 [==============================] - 0s 10ms/step - loss: 0.3091 - accuracy: 0.8715 - val_loss: 0.4932 - val_accuracy: 0.7930\n",
      "Epoch 80/100\n",
      "18/18 [==============================] - 0s 10ms/step - loss: 0.3324 - accuracy: 0.8507 - val_loss: 0.4714 - val_accuracy: 0.8047\n",
      "Epoch 81/100\n",
      "18/18 [==============================] - 0s 10ms/step - loss: 0.3177 - accuracy: 0.8681 - val_loss: 0.5021 - val_accuracy: 0.7930\n",
      "Epoch 82/100\n",
      "18/18 [==============================] - 0s 10ms/step - loss: 0.3373 - accuracy: 0.8490 - val_loss: 0.4633 - val_accuracy: 0.8086\n",
      "Epoch 83/100\n",
      "18/18 [==============================] - 0s 10ms/step - loss: 0.3264 - accuracy: 0.8524 - val_loss: 0.4754 - val_accuracy: 0.8203\n",
      "Epoch 84/100\n",
      "18/18 [==============================] - 0s 10ms/step - loss: 0.3531 - accuracy: 0.8490 - val_loss: 0.4903 - val_accuracy: 0.7891\n",
      "Epoch 85/100\n",
      "18/18 [==============================] - 0s 10ms/step - loss: 0.3552 - accuracy: 0.8333 - val_loss: 0.4834 - val_accuracy: 0.8047\n",
      "Epoch 86/100\n",
      "18/18 [==============================] - 0s 11ms/step - loss: 0.3255 - accuracy: 0.8594 - val_loss: 0.5073 - val_accuracy: 0.7852\n",
      "Epoch 87/100\n",
      "18/18 [==============================] - 0s 10ms/step - loss: 0.3267 - accuracy: 0.8646 - val_loss: 0.5197 - val_accuracy: 0.8008\n",
      "Epoch 88/100\n",
      "18/18 [==============================] - 0s 11ms/step - loss: 0.3206 - accuracy: 0.8628 - val_loss: 0.5282 - val_accuracy: 0.8008\n",
      "Epoch 89/100\n",
      "18/18 [==============================] - 0s 10ms/step - loss: 0.3455 - accuracy: 0.8524 - val_loss: 0.4867 - val_accuracy: 0.8125\n",
      "Epoch 90/100\n",
      "18/18 [==============================] - 0s 10ms/step - loss: 0.3178 - accuracy: 0.8698 - val_loss: 0.5266 - val_accuracy: 0.7930\n",
      "Epoch 91/100\n",
      "18/18 [==============================] - 0s 10ms/step - loss: 0.3370 - accuracy: 0.8576 - val_loss: 0.5351 - val_accuracy: 0.7852\n",
      "Epoch 92/100\n",
      "18/18 [==============================] - 0s 10ms/step - loss: 0.3043 - accuracy: 0.8628 - val_loss: 0.5173 - val_accuracy: 0.8008\n",
      "Epoch 93/100\n",
      "18/18 [==============================] - 0s 10ms/step - loss: 0.3268 - accuracy: 0.8663 - val_loss: 0.5271 - val_accuracy: 0.7812\n",
      "Epoch 94/100\n",
      "18/18 [==============================] - 0s 10ms/step - loss: 0.3183 - accuracy: 0.8750 - val_loss: 0.4823 - val_accuracy: 0.7930\n",
      "Epoch 95/100\n",
      "18/18 [==============================] - 0s 10ms/step - loss: 0.3124 - accuracy: 0.8646 - val_loss: 0.5420 - val_accuracy: 0.7969\n",
      "Epoch 96/100\n",
      "18/18 [==============================] - 0s 10ms/step - loss: 0.3205 - accuracy: 0.8663 - val_loss: 0.5226 - val_accuracy: 0.7852\n",
      "Epoch 97/100\n",
      "18/18 [==============================] - 0s 10ms/step - loss: 0.3139 - accuracy: 0.8715 - val_loss: 0.5941 - val_accuracy: 0.7891\n",
      "Epoch 98/100\n",
      "18/18 [==============================] - 0s 10ms/step - loss: 0.3116 - accuracy: 0.8715 - val_loss: 0.5337 - val_accuracy: 0.7969\n",
      "Epoch 99/100\n",
      "18/18 [==============================] - 0s 10ms/step - loss: 0.3026 - accuracy: 0.8750 - val_loss: 0.5475 - val_accuracy: 0.8086\n",
      "Epoch 100/100\n",
      "18/18 [==============================] - 0s 10ms/step - loss: 0.3115 - accuracy: 0.8628 - val_loss: 0.5582 - val_accuracy: 0.7773\n"
     ]
    }
   ],
   "source": [
    "train_dataset = make_dataset(train_df, y_train, epochs=100)\n",
    "eval_dataset = make_dataset(eval_df, y_eval, epochs=1, shuffle=False)\n",
    "\n",
    "# 1. model.fit\n",
    "history = model.fit(train_dataset,\n",
    "                    validation_data = eval_dataset,\n",
    "                    steps_per_epoch = 18,\n",
    "                    validation_steps = 8,\n",
    "                    epochs = 100)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "keras.estimator.model_to_estimator 将model转化为 estimator\n",
    "\n",
    "estimator.train进行训练\n",
    "\n",
    "所需要的参数：input_fn\n",
    "- function\n",
    "- return a. (features, label) b. dataset -> (feature, label)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "INFO:tensorflow:Using default config.\n",
      "WARNING:tensorflow:Using temporary folder as model directory: C:\\Users\\Awebone\\AppData\\Local\\Temp\\tmpfp_y23zg\n",
      "INFO:tensorflow:Using the Keras model provided.\n",
      "WARNING:tensorflow:You are creating an Estimator from a Keras model manually subclassed from `Model`, that was already called on some inputs (and thus already had weights). We are currently unable to preserve the model's state (its weights) as part of the estimator in this case. Be warned that the estimator has been created using a freshly initialized version of your model.\n",
      "Note that this doesn't affect the state of the model instance you passed as `keras_model` argument.\n",
      "INFO:tensorflow:Using config: {'_model_dir': 'C:\\\\Users\\\\Awebone\\\\AppData\\\\Local\\\\Temp\\\\tmpfp_y23zg', '_tf_random_seed': None, '_save_summary_steps': 100, '_save_checkpoints_steps': None, '_save_checkpoints_secs': 600, '_session_config': allow_soft_placement: true\n",
      "graph_options {\n",
      "  rewrite_options {\n",
      "    meta_optimizer_iterations: ONE\n",
      "  }\n",
      "}\n",
      ", '_keep_checkpoint_max': 5, '_keep_checkpoint_every_n_hours': 10000, '_log_step_count_steps': 100, '_train_distribute': None, '_device_fn': None, '_protocol': None, '_eval_distribute': None, '_experimental_distribute': None, '_experimental_max_worker_delay_secs': None, '_session_creation_timeout_secs': 7200, '_service': None, '_cluster_spec': <tensorflow.python.training.server_lib.ClusterSpec object at 0x0000016B4AB1A6A0>, '_task_type': 'worker', '_task_id': 0, '_global_id_in_cluster': 0, '_master': '', '_evaluation_master': '', '_is_chief': True, '_num_ps_replicas': 0, '_num_worker_replicas': 1}\n"
     ]
    }
   ],
   "source": [
    "# 2. model -> estimator -> train\n",
    "# 将model转化为estimator\n",
    "estimator = keras.estimator.model_to_estimator(model)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "WARNING:tensorflow:From f:\\condaenv\\tf2_py36\\lib\\site-packages\\tensorflow_core\\python\\ops\\resource_variable_ops.py:1630: calling BaseResourceVariable.__init__ (from tensorflow.python.ops.resource_variable_ops) with constraint is deprecated and will be removed in a future version.\n",
      "Instructions for updating:\n",
      "If using Keras pass *_constraint arguments to layers.\n",
      "WARNING:tensorflow:From f:\\condaenv\\tf2_py36\\lib\\site-packages\\tensorflow_core\\python\\training\\training_util.py:236: Variable.initialized_value (from tensorflow.python.ops.variables) is deprecated and will be removed in a future version.\n",
      "Instructions for updating:\n",
      "Use Variable.read_value. Variables in 2.X are initialized automatically both in eager and graph (inside tf.defun) contexts.\n",
      "INFO:tensorflow:Calling model_fn.\n"
     ]
    },
    {
     "ename": "ValueError",
     "evalue": "Unexpectedly found an instance of type `<class 'dict'>`. Expected a symbolic tensor instance.",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mValueError\u001b[0m                                Traceback (most recent call last)",
      "\u001b[1;32m<ipython-input-19-cddc24c70fd6>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[0;32m      1\u001b[0m \u001b[1;31m# bug 未修复\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 2\u001b[1;33m \u001b[0mestimator\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mtrain\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0minput_fn\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;32mlambda\u001b[0m \u001b[1;33m:\u001b[0m \u001b[0mmake_dataset\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mtrain_df\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0my_train\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mepochs\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;36m100\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[1;32mf:\\condaenv\\tf2_py36\\lib\\site-packages\\tensorflow_estimator\\python\\estimator\\estimator.py\u001b[0m in \u001b[0;36mtrain\u001b[1;34m(self, input_fn, hooks, steps, max_steps, saving_listeners)\u001b[0m\n\u001b[0;32m    368\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    369\u001b[0m       \u001b[0msaving_listeners\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0m_check_listeners_type\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0msaving_listeners\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 370\u001b[1;33m       \u001b[0mloss\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_train_model\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0minput_fn\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mhooks\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0msaving_listeners\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m    371\u001b[0m       \u001b[0mlogging\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0minfo\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'Loss for final step: %s.'\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mloss\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    372\u001b[0m       \u001b[1;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;32mf:\\condaenv\\tf2_py36\\lib\\site-packages\\tensorflow_estimator\\python\\estimator\\estimator.py\u001b[0m in \u001b[0;36m_train_model\u001b[1;34m(self, input_fn, hooks, saving_listeners)\u001b[0m\n\u001b[0;32m   1158\u001b[0m       \u001b[1;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_train_model_distributed\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0minput_fn\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mhooks\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0msaving_listeners\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m   1159\u001b[0m     \u001b[1;32melse\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m-> 1160\u001b[1;33m       \u001b[1;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_train_model_default\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0minput_fn\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mhooks\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0msaving_listeners\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m   1161\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m   1162\u001b[0m   \u001b[1;32mdef\u001b[0m \u001b[0m_train_model_default\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0minput_fn\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mhooks\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0msaving_listeners\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;32mf:\\condaenv\\tf2_py36\\lib\\site-packages\\tensorflow_estimator\\python\\estimator\\estimator.py\u001b[0m in \u001b[0;36m_train_model_default\u001b[1;34m(self, input_fn, hooks, saving_listeners)\u001b[0m\n\u001b[0;32m   1188\u001b[0m       \u001b[0mworker_hooks\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mextend\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0minput_hooks\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m   1189\u001b[0m       estimator_spec = self._call_model_fn(\n\u001b[1;32m-> 1190\u001b[1;33m           features, labels, ModeKeys.TRAIN, self.config)\n\u001b[0m\u001b[0;32m   1191\u001b[0m       \u001b[0mglobal_step_tensor\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mtraining_util\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mget_global_step\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mg\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m   1192\u001b[0m       return self._train_with_estimator_spec(estimator_spec, worker_hooks,\n",
      "\u001b[1;32mf:\\condaenv\\tf2_py36\\lib\\site-packages\\tensorflow_estimator\\python\\estimator\\estimator.py\u001b[0m in \u001b[0;36m_call_model_fn\u001b[1;34m(self, features, labels, mode, config)\u001b[0m\n\u001b[0;32m   1146\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m   1147\u001b[0m     \u001b[0mlogging\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0minfo\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'Calling model_fn.'\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m-> 1148\u001b[1;33m     \u001b[0mmodel_fn_results\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_model_fn\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mfeatures\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0mfeatures\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;33m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m   1149\u001b[0m     \u001b[0mlogging\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0minfo\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'Done calling model_fn.'\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m   1150\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;32mf:\\condaenv\\tf2_py36\\lib\\site-packages\\tensorflow_estimator\\python\\estimator\\keras.py\u001b[0m in \u001b[0;36mmodel_fn\u001b[1;34m(features, labels, mode)\u001b[0m\n\u001b[0;32m    286\u001b[0m         \u001b[0mfeatures\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0mfeatures\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    287\u001b[0m         \u001b[0mlabels\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0mlabels\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 288\u001b[1;33m         optimizer_config=optimizer_config)\n\u001b[0m\u001b[0;32m    289\u001b[0m     \u001b[0mmodel_output_names\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;33m[\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    290\u001b[0m     \u001b[1;31m# We need to make sure that the output names of the last layer in the model\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;32mf:\\condaenv\\tf2_py36\\lib\\site-packages\\tensorflow_estimator\\python\\estimator\\keras.py\u001b[0m in \u001b[0;36m_clone_and_build_model\u001b[1;34m(mode, keras_model, custom_objects, features, labels, optimizer_config)\u001b[0m\n\u001b[0;32m    225\u001b[0m       \u001b[0min_place_reset\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;32mnot\u001b[0m \u001b[0mkeras_model\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_is_graph_network\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    226\u001b[0m       \u001b[0moptimizer_iterations\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0mglobal_step\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 227\u001b[1;33m       optimizer_config=optimizer_config)\n\u001b[0m\u001b[0;32m    228\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    229\u001b[0m   \u001b[1;32mif\u001b[0m \u001b[0msample_weight_tensors\u001b[0m \u001b[1;32mis\u001b[0m \u001b[1;32mnot\u001b[0m \u001b[1;32mNone\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;32mf:\\condaenv\\tf2_py36\\lib\\site-packages\\tensorflow_core\\python\\keras\\models.py\u001b[0m in \u001b[0;36mclone_and_build_model\u001b[1;34m(model, input_tensors, target_tensors, custom_objects, compile_clone, in_place_reset, optimizer_iterations, optimizer_config)\u001b[0m\n\u001b[0;32m    632\u001b[0m         \u001b[0mclone\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mclone_model\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mmodel\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0minput_tensors\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0minput_tensors\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    633\u001b[0m     \u001b[1;32melse\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 634\u001b[1;33m       \u001b[0mclone\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mclone_model\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mmodel\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0minput_tensors\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0minput_tensors\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m    635\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    636\u001b[0m     if all([isinstance(clone, Sequential),\n",
      "\u001b[1;32mf:\\condaenv\\tf2_py36\\lib\\site-packages\\tensorflow_core\\python\\keras\\models.py\u001b[0m in \u001b[0;36mclone_model\u001b[1;34m(model, input_tensors, clone_function)\u001b[0m\n\u001b[0;32m    417\u001b[0m   \u001b[1;32mif\u001b[0m \u001b[0misinstance\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mmodel\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mSequential\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    418\u001b[0m     return _clone_sequential_model(\n\u001b[1;32m--> 419\u001b[1;33m         model, input_tensors=input_tensors, layer_fn=clone_function)\n\u001b[0m\u001b[0;32m    420\u001b[0m   \u001b[1;32melse\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    421\u001b[0m     return _clone_functional_model(\n",
      "\u001b[1;32mf:\\condaenv\\tf2_py36\\lib\\site-packages\\tensorflow_core\\python\\keras\\models.py\u001b[0m in \u001b[0;36m_clone_sequential_model\u001b[1;34m(model, input_tensors, layer_fn)\u001b[0m\n\u001b[0;32m    336\u001b[0m       \u001b[0minput_tensors\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mlist\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0minput_tensors\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    337\u001b[0m     \u001b[0mx\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mgeneric_utils\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mto_list\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0minput_tensors\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;36m0\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 338\u001b[1;33m     \u001b[1;32mif\u001b[0m \u001b[0mK\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mis_keras_tensor\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mx\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m    339\u001b[0m       \u001b[0morigin_layer\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mx\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_keras_history\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mlayer\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    340\u001b[0m       \u001b[1;32mif\u001b[0m \u001b[0misinstance\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0morigin_layer\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mInputLayer\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;32mf:\\condaenv\\tf2_py36\\lib\\site-packages\\tensorflow_core\\python\\keras\\backend.py\u001b[0m in \u001b[0;36mis_keras_tensor\u001b[1;34m(x)\u001b[0m\n\u001b[0;32m    985\u001b[0m                         sparse_tensor.SparseTensor)):\n\u001b[0;32m    986\u001b[0m     raise ValueError('Unexpectedly found an instance of type `' + str(type(x)) +\n\u001b[1;32m--> 987\u001b[1;33m                      '`. Expected a symbolic tensor instance.')\n\u001b[0m\u001b[0;32m    988\u001b[0m   \u001b[1;32mreturn\u001b[0m \u001b[0mhasattr\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mx\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;34m'_keras_history'\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    989\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;31mValueError\u001b[0m: Unexpectedly found an instance of type `<class 'dict'>`. Expected a symbolic tensor instance."
     ]
    }
   ],
   "source": [
    "# bug 未修复\n",
    "estimator.train(input_fn = lambda : make_dataset(train_df, y_train, epochs=100))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.10"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
